From 4bf90633eaf945e88a8ad9f752b239554ac1dfc8 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 31 Mar 2018 17:52:47 +0200 Subject: [PATCH] widget: Cache clip from creating render node When the clip changes that is passed to a snapshot function, we need to create eventual cached render nodes because they might not have drawn their whole area before. Fixes issues with redrawing when scrolling. --- gtk/gtksnapshot.c | 17 +++++++++++++++++ gtk/gtksnapshotprivate.h | 12 +++++++----- gtk/gtkwidget.c | 22 ++++++++++++++++++++-- gtk/gtkwidgetprivate.h | 6 +++++- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index ead1e5acaf..14514a9689 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -1594,6 +1594,23 @@ gtk_snapshot_append_color (GtkSnapshot *snapshot, gsk_render_node_unref (node); } +gboolean +gtk_snapshot_get_clip (GtkSnapshot *snapshot, + graphene_rect_t *out_clip) +{ + const GtkSnapshotState *current_state = gtk_snapshot_get_current_state (snapshot); + + if (!current_state->has_clip) + return FALSE; + + graphene_rect_offset_r (¤t_state->clip, + - current_state->translate_x, + - current_state->translate_y, + out_clip); + + return TRUE; +} + /** * gtk_snapshot_clips_rect: * @snapshot: a #GtkSnapshot diff --git a/gtk/gtksnapshotprivate.h b/gtk/gtksnapshotprivate.h index e5ddb600f0..6e34d17c22 100644 --- a/gtk/gtksnapshotprivate.h +++ b/gtk/gtksnapshotprivate.h @@ -99,11 +99,13 @@ struct _GtkSnapshotClass { GObjectClass parent_class; /* it's really GdkSnapshotClass, but don't tell anyone! */ }; -GtkSnapshot * gtk_snapshot_new_child (GtkSnapshot *parent, - const char *name, - ...) G_GNUC_PRINTF (2, 3); -void gtk_snapshot_append_node_internal (GtkSnapshot *snapshot, - GskRenderNode *node); +GtkSnapshot * gtk_snapshot_new_child (GtkSnapshot *parent, + const char *name, + ...) G_GNUC_PRINTF (2, 3); +void gtk_snapshot_append_node_internal (GtkSnapshot *snapshot, + GskRenderNode *node); +gboolean gtk_snapshot_get_clip (GtkSnapshot *snapshot, + graphene_rect_t *out_clip); G_END_DECLS diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 3d9f967ce5..039bc746fb 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -4021,6 +4021,7 @@ gtk_widget_queue_draw (GtkWidget *widget) priv->draw_needed = TRUE; g_clear_pointer (&priv->render_node, gsk_render_node_unref); + priv->render_node_has_clip = FALSE; gtk_widget_invalidate_paintable_contents (widget); if (_gtk_widget_get_has_surface (widget) && _gtk_widget_get_realized (widget)) @@ -13816,6 +13817,8 @@ gtk_widget_snapshot (GtkWidget *widget, { GtkWidgetPrivate *priv = widget->priv; graphene_rect_t offset_clip; + graphene_rect_t clip; + gboolean has_clip; double opacity; if (!_gtk_widget_is_drawable (widget)) @@ -13841,13 +13844,28 @@ gtk_widget_snapshot (GtkWidget *widget, if (opacity <= 0.0) return; - if (priv->draw_needed) + has_clip = gtk_snapshot_get_clip (snapshot, &clip); + + if (priv->draw_needed || + (priv->render_node_has_clip && (!has_clip || !graphene_rect_contains_rect (&priv->render_node_clip, &clip)))) { GskRenderNode *render_node; + render_node = gtk_widget_create_render_node (widget, snapshot); - /* This can happen when nested drawing happens and a widget contains itself */ + /* This can happen when nested drawing happens and a widget contains itself + * or when we replace a clipped area */ g_clear_pointer (&priv->render_node, gsk_render_node_unref); priv->render_node = render_node; + if (has_clip) + { + priv->render_node_clip = clip; + priv->render_node_has_clip = TRUE; + } + else + { + priv->render_node_has_clip = FALSE; + } + priv->draw_needed = FALSE; } diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index ed65646ee2..2cc974a5e1 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -78,6 +78,7 @@ struct _GtkWidgetPrivate /* Queue-draw related flags */ guint draw_needed : 1; + guint render_node_has_clip : 1; /* Expand-related flags */ guint need_compute_expand : 1; /* Need to recompute computed_[hv]_expand */ @@ -145,8 +146,11 @@ struct _GtkWidgetPrivate /* The widget's requested sizes */ SizeRequestCache requests; - /* The render node we draw or %NULL if not yet created. */ + /* The render node we draw or %NULL if not yet created.*/ GskRenderNode *render_node; + /* The clip that existed when the render node was drawn + * Ignored when render_node_has_clip == FALSE */ + graphene_rect_t render_node_clip; GSList *paintables; -- 2.30.2